package com.ruoyi.web.util.pdf;

import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;
import com.ruoyi.web.service.TokenSignService;
import org.bouncycastle.asn1.esf.SignaturePolicyIdentifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashMap;

@Component
public class EssMakeSignature extends MakeSignature {

    @Autowired
    public TokenSignService signTokenService;

    public static EssMakeSignature essMakeSignature;

    @PostConstruct
    public void init() {
        essMakeSignature = this;
    }

    public static void signDetached(PdfSignatureAppearance sap, ExternalDigest externalDigest, ExternalSignature externalSignature,
                                    Certificate[] chain, Collection<CrlClient> crlList, OcspClient ocspClient,
                                    TSAClient tsaClient, int estimatedSize, com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard sigtype, String UKID) throws Exception {
        signDetached(sap, externalDigest, externalSignature, chain, crlList, ocspClient, tsaClient, estimatedSize, sigtype, (SignaturePolicyIdentifier) null,UKID);
    }

    public static void signDetached(PdfSignatureAppearance sap, ExternalDigest externalDigest, ExternalSignature externalSignature, Certificate[] chain, Collection<CrlClient> crlList, OcspClient ocspClient,
                                    TSAClient tsaClient, int estimatedSize, com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard sigtype, SignaturePolicyIdentifier signaturePolicy,
                                    String UKID) throws Exception {
        Collection<byte[]> crlBytes = null;
        int i = 0;
        while (crlBytes == null && i < chain.length)
            crlBytes = processCrl(chain[i++], crlList);
        if (estimatedSize == 0) {
            estimatedSize = 8192;
            if (crlBytes != null) {
                for (byte[] element : crlBytes) {
                    estimatedSize += element.length + 10;
                }
            }
            if (ocspClient != null)
                estimatedSize += 4192;
            if (tsaClient != null)
                estimatedSize += 4192;
        }
        sap.setCertificate(chain[0]);
        if (sigtype == com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard.CADES) {
            sap.addDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL2);
        }
        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, sigtype == com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard.CADES ? PdfName.ETSI_CADES_DETACHED : PdfName.ADBE_PKCS7_DETACHED);
        dic.setReason(sap.getReason());
        dic.setLocation(sap.getLocation());
        dic.setSignatureCreator(sap.getSignatureCreator());
        dic.setContact(sap.getContact());
        dic.setDate(new PdfDate(sap.getSignDate())); // time-stamp will over-rule this
        sap.setCryptoDictionary(dic);

        HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
        exc.put(PdfName.CONTENTS, new Integer(estimatedSize * 2 + 2));
        sap.preClose(exc);
//        String hashAlgorithm = externalSignature.getHashAlgorithm();
        String hashAlgorithm = "SHA256";
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, externalDigest, false);
        if (signaturePolicy != null) {
            sgn.setSignaturePolicy(signaturePolicy);
        }
        InputStream data = sap.getRangeStream();
        byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(hashAlgorithm));

        byte[] ocsp = null;
        if (chain.length >= 2 && ocspClient != null) {
            ocsp = ocspClient.getEncoded((X509Certificate) chain[0], (X509Certificate) chain[1], null);
        }
        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, ocsp, crlBytes, sigtype);
        //TODO
//        byte[] extSignature = NetSignAgentUtils.getSign(UKID,sh);
        byte[] extSignature = essMakeSignature.signTokenService.getSignValue(UKID,sh);
        if (extSignature ==null){
            throw new NullPointerException("签名值为空");
        }
        sgn.setExternalDigest(extSignature, null, "SM2");
//        sgn.setExternalDigest(extSignature, null, externalSignature.getEncryptionAlgorithm());
        byte[] encodedSig = sgn.getEncodedPKCS7(hash, tsaClient, ocsp, crlBytes, sigtype);
        if (estimatedSize < encodedSig.length)
            throw new IOException("Not enough space");
        byte[] paddedSig = new byte[estimatedSize];
        System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
        PdfDictionary dic2 = new PdfDictionary();
        dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
        sap.close(dic2);
    }
}
